{
 "cells": [
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# nvImageCodec examples"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "import cv2\n",
    "import numpy as np\n",
    "from matplotlib import pyplot as plt"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Setting resource folder"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "resources_dir = os.getenv(\"PYNVIMGCODEC_EXAMPLES_RESOURCES_DIR\", \"../assets/images/\")"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Import nvImageCodec module and create Decoder and Encoder"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from nvidia import nvimgcodec\n",
    "decoder = nvimgcodec.Decoder()\n",
    "encoder = nvimgcodec.Encoder()"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Load and decode Jpeg image with nvImageCodec"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "with open(resources_dir + \"tabby_tiger_cat.jpg\", 'rb') as in_file:\n",
    "    data = in_file.read()\n",
    "    nv_img_cat = decoder.decode(data)"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Save image to bmp file with nvImageCodec"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "with open(\"cat-jpg-o.bmp\", 'wb') as out_file:\n",
    "    data = encoder.encode(nv_img_cat, \"bmp\")\n",
    "    out_file.write(data)"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Read back with OpenCV just saved (with nvImageCodec) bmp image "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "cv_img_bmp = cv2.imread(\"cat-jpg-o.bmp\")\n",
    "cv_img_bmp = cv2.cvtColor(cv_img_bmp, cv2.COLOR_BGR2RGB)\n",
    "plt.imshow(cv_img_bmp)"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Load and decode Jpeg2000 (in jp2 container) image with nvImageCodec in one read function"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "nv_img = decoder.read(resources_dir + \"cat-1046544_640.jp2\")"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Save image to jpg file with nvImageCodec in one write function"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "encoder.write(\"cat-jp2-o.jpg\", nv_img)"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Read back with OpenCV just save (with nvImageCodec) bmp image "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "image = cv2.imread(\"cat-jp2-o.jpg\")\n",
    "image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)\n",
    "plt.imshow(image)"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Load jpg with nvImageCodec"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "nv_img_jpg = decoder.read(resources_dir + \"tabby_tiger_cat.jpg\")"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Save as Jpeg 2000 with nvImageCodec"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "encoder.write(\"cat-jpg-o.j2k\", nv_img_jpg)"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Read back with OpenCV just saved (with nvImageCodec) j2k image "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "image = cv2.imread(\"cat-jpg-o.j2k\")\n",
    "image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)\n",
    "plt.imshow(image)"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Passing decoding parameters"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Decode jpeg with Exif orientation - by default it applies exif orientation"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "nv_img_jpg = decoder.read(resources_dir+ \"f-exif-8.jpg\")\n",
    "encoder.write(\"f-exif-8.bmp\", nv_img_jpg)\n",
    "image = cv2.imread(\"f-exif-8.bmp\")\n",
    "image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)\n",
    "plt.imshow(image)"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let assume we would like to ignore exif orientation"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "dec_params = nvimgcodec.DecodeParams(apply_exif_orientation=False)\n",
    "nv_img_jpg = decoder.read(resources_dir + \"f-exif-8.jpg\", dec_params)\n",
    "encoder.write(\"f-wo-exif.bmp\", nv_img_jpg)\n",
    "image = cv2.imread(\"f-wo-exif.bmp\")\n",
    "image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)\n",
    "plt.imshow(image)"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Passing encoding parameters"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Changing quality and chroma subsampling in jpeg"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "nv_img_jpg = decoder.read(resources_dir + \"tabby_tiger_cat.jpg\")\n",
    "enc_params = nvimgcodec.EncodeParams(quality=5, chroma_subsampling=nvimgcodec.ChromaSubsampling.CSS_GRAY)\n",
    "encoder.write(\"cat-q5-gray.jpg\", nv_img_jpg, params=enc_params)\n",
    "                    \n",
    "image = cv2.imread(\"cat-q5-gray.jpg\")\n",
    "image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)\n",
    "plt.imshow(image)"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Jpeg optimized huffman and progressive encoding"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "nv_img_jpg = decoder.read(resources_dir + \"tabby_tiger_cat.jpg\")\n",
    "encoder.write(\"cat-q75.jpg\", nv_img_jpg, params=nvimgcodec.EncodeParams(quality=75))\n",
    "encoder.write(\"cat-q75-optimized_huffman.jpg\", nv_img_jpg, params=nvimgcodec.EncodeParams(\n",
    "    quality=75, jpeg_encode_params = nvimgcodec.JpegEncodeParams(optimized_huffman=True, progressive=True)))\n",
    "\n",
    "print(\"default huffman file size:\", os.path.getsize(\"cat-q75.jpg\"))\n",
    "print(\"optimized huffman file size:\", os.path.getsize(\n",
    "    \"cat-q75-optimized_huffman.jpg\"))\n",
    "\n",
    "image = cv2.imread(\"cat-q75-optimized_huffman.jpg\")\n",
    "image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)\n",
    "plt.imshow(image)\n"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Encode lossless and lossy with jpeg2000"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import ctypes\n",
    "nv_img_jpg = decoder.read(resources_dir + \"tabby_tiger_cat.jpg\")\n",
    "\n",
    "encoder.write(\"cat-psnr25.j2k\", nv_img_jpg, params=nvimgcodec.EncodeParams(target_psnr=25))\n",
    "\n",
    "jpeg2k_encode_params = nvimgcodec.Jpeg2kEncodeParams(reversible=True)\n",
    "encoder.write(\"cat-lossless.j2k\", nv_img_jpg, params=nvimgcodec.EncodeParams(jpeg2k_encode_params=jpeg2k_encode_params))\n",
    "\n",
    "jpeg2k_encode_params.num_resolutions = 2\n",
    "jpeg2k_encode_params.code_block_size = (32, 32)\n",
    "jpeg2k_encode_params.bitstream_type = nvimgcodec.Jpeg2kBitstreamType.JP2\n",
    "jpeg2k_encode_params.prog_order = nvimgcodec.Jpeg2kProgOrder.LRCP\n",
    "encoder.write(\"cat-lossless-2decomps.j2k\", nv_img_jpg, params=nvimgcodec.EncodeParams(jpeg2k_encode_params=jpeg2k_encode_params))\n",
    "\n",
    "print(\"lossy file size:\", os.path.getsize(\"cat-psnr25.j2k\"))\n",
    "print(\"lossless file size:\", os.path.getsize(\"cat-lossless.j2k\"))\n",
    "print(\"lossless 2 decomposition levels file size:\",  os.path.getsize(\"cat-lossless-2decomps.j2k\"))\n",
    "image = cv2.imread(\"cat-psnr25.j2k\")\n",
    "image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)\n",
    "plt.imshow(image)"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can specify allowed backends used for decoding"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "gpu_dec = nvimgcodec.Decoder(backends=[nvimgcodec.Backend(nvimgcodec.GPU_ONLY, load_hint=0.5), nvimgcodec.Backend(nvimgcodec.HYBRID_CPU_GPU)])\n",
    "cpu_dec = nvimgcodec.Decoder(backend_kinds=[nvimgcodec.CPU_ONLY])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%time\n",
    "nv_img_j2k = cpu_dec.read(resources_dir + \"cat-1046544_640.jp2\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%time\n",
    "nv_img_j2k = gpu_dec.read(resources_dir + \"cat-1046544_640.jp2\")\n"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The same way we can create Encoder with allowed backends."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "gpu_enc = nvimgcodec.Encoder(backends=[nvimgcodec.Backend(nvimgcodec.GPU_ONLY, load_hint=0.5)\n",
    "                             , nvimgcodec.Backend(nvimgcodec.HYBRID_CPU_GPU)])\n",
    "cpu_enc = nvimgcodec.Encoder(backend_kinds=[nvimgcodec.CPU_ONLY])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "gpu_enc.write(\"cat_gpu_out.jpg\", nv_img_j2k)"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Currently there is no CPU encoder available for jpeg so having cpu_enc we can write for example to bmp"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "cpu_enc.write(\"cat_cpu_out.bmp\", nv_img_j2k)"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Support of \\_\\_cuda_array_interface\\_\\_"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(nv_img_j2k.__cuda_array_interface__)\n",
    "print(nv_img_j2k.shape)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Support of \\_\\_array_interface\\_\\_"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "It is possible to pass to nvImageCodec host ndarray by object which supports \\_\\_array_interface\\_\\_ as for example image (numpy.ndarray) created by OpenCV "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "cv_img = cv2.imread(resources_dir + \"Weimaraner.bmp\")\n",
    "cv_img = cv2.cvtColor(cv_img, cv2.COLOR_BGR2RGB)\n",
    "\n",
    "print(type(cv_img))\n",
    "print(cv_img.__array_interface__)\n",
    "\n",
    "nv_h_img = nvimgcodec.as_image(cv_img)\n",
    "gpu_enc.write(\"Weimaraner_ai_out.jpg\", nv_h_img)\n",
    "\n",
    "image = cv2.imread(\"Weimaraner_ai_out.jpg\")\n",
    "image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)\n",
    "plt.imshow(image)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "If we use cpu() method of Image object it would create new Image with copied content to host buffer."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "nv_img = cpu_dec.read(resources_dir + \"cat-1046544_640.jp2\")\n",
    "nv_h_img = nv_img.cpu()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Image with host buffer supports \\_\\_array_interface\\_\\_  (but can't return a proper \\_\\_cuda_array_interface\\_\\_)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(nv_h_img.__array_interface__)\n",
    "print(nv_h_img.__cuda_array_interface__)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "so we can pass such Image to functions which accept and can use this interface like imshow from matplotlib library"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "plt.imshow(nv_h_img)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can also create a zero-copy view of this image with numpy and process it with OpenCV"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "np_img = np.asarray(nv_h_img)\n",
    "kernel = np.ones((5, 5), np.float32)/25\n",
    "dst = cv2.filter2D(np_img, -1, kernel)\n",
    "plt.subplot(121), plt.imshow(np_img), plt.title('Original')\n",
    "plt.xticks([]), plt.yticks([])\n",
    "plt.subplot(122), plt.imshow(dst), plt.title('Averaging')\n",
    "plt.xticks([]), plt.yticks([])\n",
    "plt.show()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "There is also method cuda() which can be used to convert an Image with a host buffer to an Image with copied contents to a device buffer."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(nv_h_img.__cuda_array_interface__)\n",
    "nv_new_cuda_img = nv_h_img.cuda()\n",
    "print(nv_new_cuda_img.__cuda_array_interface__)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can check whether Image keeps a host or a device buffer by reading the buffer_kind property"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(\"Host image buffer kind: \", nv_h_img.buffer_kind)\n",
    "print(\"Device image buffer kind: \", nv_new_cuda_img.buffer_kind)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Managing lifetime of decoder resources using \"with\" statement"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "with nvimgcodec.Decoder() as decoder_2:\n",
    "    nv_img = decoder_2.read(resources_dir + \"cat-1046544_640.jp2\")\n",
    "    plt.imshow(nv_img.cpu())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Similarly for encoder resources "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "with nvimgcodec.Encoder() as encoder_2:\n",
    "    encoder_2.write(\"cat-1046544_640_out.jpg\", nv_img)\n",
    "    image = cv2.imread(\"cat-1046544_640_out.jpg\")\n",
    "    image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)\n",
    "    plt.imshow(image)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3.8.10 64-bit",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.10"
  },
  "orig_nbformat": 4,
  "vscode": {
   "interpreter": {
    "hash": "916dbcbb3f70747c44a77c7bcd40155683ae19c65e1c03b4aa3499c5328201f1"
   }
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
